<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>48、DOM的diffing算法</title>
</head>
<body>
  <div id="test"></div>

  <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
  <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
  <script src="https://cdn.staticfile.org/prop-types/15.6.1/prop-types.js"></script>

  <!-- 
    经典题：
    1、react/vue中的key有什么作用？（key的内部原理是什么？）
      虚拟dom中key的作用：
        1）简单的说，key时虚拟dom对象的标识，在更新显示时key起着极其重要的作用。
        2）详细的说，当状态中的数据发生变化时，react会根据【新数据】生成【新的虚拟dom】，
                    随后react进行【新虚拟dom】与【旧虚拟dom】的diff比较，比较规则如下：

                    a.旧虚拟DOM中找到了与新虚拟DOM相同的key：
                      (1)若虚拟dom中内容没变，直接使用之前的真实dom
                      (2)若虚拟dom中内容变了，则生成新的真实dom，随后替换掉页面中之前的真实dom

                    b.旧虚拟DOM中未找到与新虚拟DOM相同的key
                      根据数据创建新的真实DOM,随后渲染到页面
      用index作为key可能会引发的问题：
        a. 若对数据进行：逆序添加、逆序删除等破坏顺序操作；会产生没有必要的真实DOM更新===》界面效果没问题，但效率低
        b. 如果结构中还包含输入类的DOM；会产生错误DOM更新===》界面有问题
        c.注意！如果不存在对数据的逆序添加、逆序删除等破坏顺序操作。仅用于渲染列表用于展示，使用index作为key是没有问题的

      开发中如何选择key?
        1)最好使用每条数据的唯一标识作为key，比如id、手机号、身份证号、学号等唯一标识
        2)如果确定只是简单的展示数据，用index也是可以的
                    
    2、为什么遍历列表时，key最好不要用index？
  -->

  <script type="text/babel">
    /**
     * 慢动作回放====使用index索引值为key
     *    数据：
     *      {id: 1, name: '小张', age: 8},
            {id: 2, name: '小李', age: 19},
          初始的虚拟dom
            <li key=0>小张---8</li>
            <li key=1>小李---19</li>

          更新后的数据：
            {id: 3, name: '小王', age: 20}
            {id: 1, name: '小张', age: 18},
            {id: 2, name: '小李', age: 19},
          更新后的虚拟dom
            <li key=0>小王---20</li>
            <li key=1>小张---18</li>
            <li key=2>小李---19</li>
        
        旧虚拟dom和新虚拟dom比较，旧虚拟dom中找到了新虚拟dom相同的key，虚拟dom中内容变了，则生成新的真实dom，随后替换掉页面中之前的真实dom


       慢动作回放====使用id唯一标识作为key
          初始数据：
            {id: 1, name: '小张', age: 8},
            {id: 2, name: '小李', age: 19},
          初始的虚拟dom
            <li key=1>小张---8</li>
            <li key=2>小李---19</li>

          更新后的数据：
            {id: 3, name: '小王', age: 20}
            {id: 1, name: '小张', age: 18},
            {id: 2, name: '小李', age: 19},
          更新后的虚拟dom
            <li key=3>小王---20</li>
            <li key=1>小张---18</li>
            <li key=2>小李---19</li>
        
        旧虚拟dom和新虚拟dom比较，只要创建一个新的真实dom<li key=3>小王---20</li>
     */
    class Person extends React.Component {
      state = {
        persons: [
          {id: 1, name: '小张', age: 8},
          {id: 2, name: '小李', age: 19},
        ]
      }

      add = () => {
        const {persons} = this.state
        const p = {id: persons.length+1, name: '小王', age: 20}
        this.setState({
          persons: [p, ...persons],
        })
      }

      render() {
        return (
          <div>
            <h2>展示人员信息</h2>
            <button onClick={this.add}>添加一个小王</button>
            <ul>
              {
                this.state.persons.map((personObj, index) => {
                  return <li key={index}>{personObj.name}---{personObj.age}<input type="text" /></li>
                })
              }  
            </ul>
            <hr/> 
            <hr/>
            <h3>使用id作为key</h3>
            <ul>
              {
                this.state.persons.map((personObj, index) => {
                  return <li key={personObj.id}>{personObj.name}---{personObj.age}<input type="text" /></li>
                })
              }
            </ul> 
          </div>
        )
      }
    }
    ReactDOM.render(<Person />, document.getElementById('test'))

    class Time extends React.Component{
      state = {
        date: new Date()
      }

      componentDidMount() {
        setInterval(() => {
          this.setState({
            date: new Date()
          })
        }, 1000)
      }

      render() {
        const {count} = this.state
        return(
          <div>
            <h2>hello</h2>
            <input type="text" />
            <span>
              现在是：{this.state.date.toTimeString()}
              <input type="text" />
            </span>
            
          </div>
        )
      }

      // 组件更新完毕的钩子
      componentDidUpdate(props, state) {
        console.log('count-componentDidUpdate', props, state)
      }
    }

    // ReactDOM.render(<Time />, document.getElementById('test'))
  </script>
</body>
</html>